#pragma once

#include <iostream>
#include <vector>
#include "Sem.hpp"
#include "Mutex.hpp"

using namespace SemModule;
using namespace MutexMod;
const int gcap = 5;

template <typename T>
class AnQueue
{
public:
    AnQueue()
        : ring_queue(gcap),
          _capacity(gcap),
          // 这里不能初始为0,初始为0时申请信号量会阻塞
          _blank_data(gcap),
          _p_step(0),
          _data_sem(0),
          _c_step(0)
    {
    }

    void EnterQueue(const T &in)
    {
        // _p_mutex.lock();//放在这里也对，但是效率不高
        // 先申请信号量
        _blank_data.P();
        {
            // 类似于看电影先买票在排队检票，比先排队等到你在买票效率高
            // _p_mutex.lock();
            MutexProtect mp(&_p_mutex);
            // 写入数据
            ring_queue[_p_step] = in;
            _p_step++;
            // 保持环形队列
            _p_step %= gcap;

            // _blank_data.V();
            _data_sem.V();
            // _p_mutex.unlock();
        }
    }

    T Pop()
    {
        
        T out = ring_queue[_c_step];
        // 先申请信号量
        _data_sem.P();
        {
            // _c_mutex.lock();
            MutexProtect mp(&_p_mutex);
            // 获得数据，所以原来的数据会被覆盖
            
            _c_step++;
            _c_step %= gcap;

            _blank_data.V();

            // _c_mutex.unlock();
        }
        return out;

    }

    ~AnQueue()
    {
    }

private:
    std::vector<T> ring_queue;
    int _capacity;

    // 生产者关心的是空的位置
    Sem _blank_data;
    int _p_step;

    // 消费者关心的是有数据的位置
    Sem _data_sem;
    int _c_step;

    // 维护多生产，多消费，2把锁
    Mutex _c_mutex;
    Mutex _p_mutex;
};